package org.OpenGeoPortal.Servlet;

import java.io.FileInputStream;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//import java.util.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;

import com.sun.syndication.feed.module.georss.*;
import com.sun.syndication.feed.module.georss.geometries.*;
import com.sun.syndication.feed.synd.*;
import com.sun.syndication.io.*;

import edu.harvard.hul.ois.hgl.servlet.Servlet;
import edu.harvard.hul.util.HGLUtilities;


/**
 * Servlet implementation class HGLGeoRSS
 */
public class OGPGeoRSSFeed extends HttpServlet {
	
	
    private static String user;
    private static String password;
    private static String pass;
    private static String server;
    private static String jdbcConnect;
    private static String driver = "oracle.jdbc.OracleDriver";
	
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public HGLGeoRSS() {
        super();
    }

	/**
	 * @see Servlet#init(ServletConfig)
	 */
	public void init(ServletConfig config) throws ServletException {

	}

	/**
	 * @see Servlet#getServletConfig()
	 */
	public ServletConfig getServletConfig() {
		return null;
	}

	/**
	 * @see Servlet#getServletInfo()
	 */
	public String getServletInfo() {
		return null; 
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse res) throws ServletException, IOException {
	    res.setContentType("application/xml; charset=UTF-8");
        
	    getProps();

	    /* Needs to merge with opengeoportal Solr index */
	    // Set initial type to point
	    boolean point = true; 
	    boolean envelope = false;
	    int bbSearch = 0;
	    
	    String[] splitKeywords = new String[4];
	    String geometryOption = "point"; // or 'envelope'
	    String[] bbCoords = new String[4];
	    
	    // Set a default string on the query
	    String UserQuery = "Boston";
	    String _formData = "";
        boolean useCoordsInQ = false;
        boolean useOnlyCoords = false;
        String query;
        
	    UserQuery = request.getParameter("UserQuery");
	    geometryOption = request.getParameter("GeometryType");
	    System.out.println("Geometry option = "+geometryOption);
	    
	    if (request.getParameter("BBSearchOption") == null || request.getParameter("BBSearchOption").equals("")) {
	    	bbSearch = 0;
	    } else {
		    bbSearch = Integer.parseInt(request.getParameter("BBSearchOption"));
	    }
	    
	    switch (bbSearch) {
		    case 0:
		    case 1: case 2: bbCoords[0] = request.getParameter("minx");
				     		bbCoords[1] = request.getParameter("miny");
				     		bbCoords[2] = request.getParameter("maxx");
				     		bbCoords[3] = request.getParameter("maxy");
				     		break;
		    default:
	    }
	    
	    _formData = UserQuery;
	    
	    // Option to allow search based on extent
        String useCoords = "off";

        if (_formData != null && !_formData.equals("")) {
            _formData = stringScrubber(_formData);
            splitKeywords = HGLUtilities.parseSearchText(_formData);
        } else {
            splitKeywords[0] = "Boston";
        }

        // Process the geometry type
        if (geometryOption != null && !geometryOption.equals("")) {
            if (geometryOption.equalsIgnoreCase("point")) {
            	point = true;
            	envelope = false;
            } else if (geometryOption.equalsIgnoreCase("envelope")) {
            	envelope = true;
            	point = false;
            } else {
            	point = true;
            	envelope = false;
            }
        } else {
        	point = true;
        	envelope = false;
        }
                
	    switch (bbSearch) {
		    case 0: query = formatBasicQuery(splitKeywords, 1, 1, false, false, "","","","");
		    		break;
		    case 1: query = formatBasicQuery(splitKeywords, 1, 1, true, false, bbCoords[0], bbCoords[1], bbCoords[2], bbCoords[3]);
		    		break;
		    case 2: query = formatBasicQuery(splitKeywords, 1, 1, false, true, bbCoords[0], bbCoords[1], bbCoords[2], bbCoords[3]);
				    break;
		    default: query = formatBasicQuery(splitKeywords, 1, 1, false, false, "","","","");
	    }
        
        try {
        	HGLUtilities.writeGenericFile("query.txt", "/home/hgl/prod/arcgis/DynamicFiles", query, 1);
        } catch (Exception o) {
        	o.printStackTrace();
        }
        
        SyndFeed feed = new SyndFeedImpl();
        feed.setFeedType("rss_2.0");

        feed.setTitle("HGL GeoRSS feed");
        feed.setLink("http://hgl.harvard.edu:8080/HGL/HGLGeoRSS?UserQuery=Boston");
        feed.setDescription("Data streamed from the Harvard Geospatial Library");

        List entries = new ArrayList();

        try {
        	entries = runQuery(query, res, envelope);
        } catch (Exception grrr) {
        	grrr.printStackTrace();
        }
        
        feed.setEntries(entries);

        SyndFeedOutput output = new SyndFeedOutput();
        
        try {
           output.output(feed, res.getWriter());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

	public static List runQuery(String query, HttpServletResponse res, boolean envelope) throws IOException {
	      
		//double[] _XY_ = new double[3];
		List entries = new ArrayList();
        SyndEntry entry;
        SyndContent description;

		    java.sql.Connection _con = null;

		    String theQuery = query;

		    // Fill the parameters from the .properties file
	        getProps();

		        try {
		            Class.forName(driver).newInstance();
		            _con = java.sql.DriverManager.getConnection(jdbcConnect, user, pass);

		            Statement stmnt = _con.createStatement();
		            ResultSet rs = stmnt.executeQuery(theQuery);

		            while (rs.next()) {
		        		entry = new SyndEntryImpl();
		                // <title> start of new element....
		                entry.setTitle(rs.getString("DESCRIPTION"));
		                entry.setLink("http://hgl.harvard.edu:8080/HGL/hgl.jsp?command=MetaLib&MetaLibID="+rs.getInt("HGL_LAYER_ID"));
		                                         

		                entry.setPublishedDate(new Date());
		                description = new SyndContentImpl();
		                description.setType("text/plain");
		                description.setValue(rs.getString("PUB_245A")+ " : " + rs.getString("PUB_520A"));
		                entry.setDescription(description);
		                entries.add(entry);
		                
		                GeoRSSModule geoRSSModule = new SimpleModuleImpl();

		                if (envelope) {
			                //Envelope box = new Envelope(rs.getFloat("MINX"),rs.getFloat("MINY"),rs.getFloat("MAXX"),rs.getFloat("MAXY"));
			                Envelope box = new Envelope(rs.getFloat("MAXX"),rs.getFloat("MAXY"),rs.getFloat("MINX"),rs.getFloat("MINY"));
			                geoRSSModule.setGeometry(box);
		                } else {
			                geoRSSModule.setPosition(new Position(((rs.getFloat("MAXY") + rs.getFloat("MINY"))/2),((rs.getFloat("MAXX") + rs.getFloat("MINX"))/2)));		                	
		                }
		                
		                entry.getModules().add(geoRSSModule);
		            }

		            rs.close();
		            stmnt.close();
		            _con.close();

		        } catch (InstantiationException e) {
		            e.printStackTrace();
		        } catch (IllegalAccessException e) {
		            e.printStackTrace();
		        } catch (ClassNotFoundException e) {
		            e.printStackTrace();
		        } catch (SQLException e) {
		            e.printStackTrace();
		        }
		        
		      return entries;
		  }
	
    public static void getProps() {

        Properties props = new Properties();
    
        try {
            props.load(new FileInputStream("/home/hgl/prod/arcgis/DynamicFiles/hglgs.properties"));
            user = props.getProperty("user");
            password = props.getProperty("password");
            pass = props.getProperty("pass");
            server = props.getProperty("server");
            jdbcConnect = props.getProperty("jdbcConnection");

            //If value of message variable is null assign default value "Hello World"
            //if(user == null) {
            //  user = new String("cga");
            //  password = "cgabrowse";
            //}
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Format an HGL Oracle Intermedia query based on user input from the maim HGL interface.
     * @param myEntries - Array of user entries.
     * @return Returns a formatted query.
     *
     * @param sort: 1 = none, 
     *              2 = TITLE 
     *              3 = SOURCE 
     *              4 = DATE
     *              5 = SCALE
     * @param option: 1 = normal query
     *                2 = just get a count of the number of results
     */
    public String formatBasicQuery( String[] myEntries,
                                    int sort,
                                    int option,
                                    boolean useCoords,
                                    boolean onlyCoords,
                                    String minx,
                                    String miny,
                                    String maxx,
                                    String maxy) {

        //-- Pre-can the browse collection searches somehow
        
        String keyword = "";
        String title = "";
        String keyList = "";
        String placeList = "";

        String theQuery       = "";
        String baseQuery      = "";
        if (option == 1) {

          baseQuery = "SELECT DESCRIPTION, HGL_LAYER_ID, PUB_245A, PUB_520A, HGL_LAYER_ID, MINX, MAXX, MINY, MAXY ";

                  switch (sort) {
                      case 1: baseQuery = baseQuery + " FROM GS_NEW ";
                              break;
                      case 2: baseQuery = baseQuery + " ,p.met_xml.extract('/metadata/idinfo/citation/citeinfo/title/text()').getStringVal() as TITLE  FROM GS_NEW ";
                              break;
                      case 3: baseQuery = baseQuery + " ,p.met_xml.extract('/metadata/idinfo/dataqual/lineage/srcinfo/srccite/citeinfo/origin/text()').getStringVal() as SOURCE  FROM GS_NEW ";
                              break;
                      case 4: baseQuery = baseQuery + " ,p.met_xml.extract('/metadata/idinfo/citation/citeinfo/serinfo/issue/text()').getStringVal() as HGLDATE  FROM GS_NEW ";
                              break;
                      case 5: baseQuery = baseQuery + " ,p.met_xml.extract('/metadata/idinfo/citation/citeinfo/edition/text()').getStringVal() as SCALE  FROM GS_NEW ";
                              break;
                      default: baseQuery = baseQuery + " FROM GS_NEW ";
                              break;
                  }
        } else {
            baseQuery = "SELECT DESCRIPTION, HGL_LAYER_ID, PUB_245A, PUB_520A, HGL_LAYER_ID, MINX, MAXX, MINY, MAXY FROM GS_NEW ";
        }

        /*  WHAT IF IT'S JUST AN ENVELOPE SEARCH?? */
        String txtMapextWithin = " MINX > " + minx + " AND MINY > " + miny + " AND MAXX < " + maxx + " AND MAXY < " + maxy + " ";
        // query update 1/10/05
        String txtMapextOverlap = " ((MINX > " + minx + " AND MINY > " + miny + " AND MAXX < " + maxx + " AND MAXY < " + maxy + ")" +
                                  " OR (((" + maxx + " < MAXX AND " + maxx + " > MINX)  " +
                                  " OR (" + minx + " < MAXX AND " + minx + " > MINX)) " +
                                  " AND ((" + maxy + " < MAXY AND " + maxy + " > MINY) " +
                                  " OR (" + miny + " < MAXY AND " + miny + " > MINY)))) ";

        String endQuery = " AND ROWNUM <= 2000";
          switch (sort) {
              case 1: ;
                      break;
              case 2: endQuery = " AND ROWNUM <= 2000 ORDER BY DESCRIPTION";   // TITLE  FROM GS_NEW ";
                      break;
              case 3: endQuery = " AND ROWNUM <= 2000 ORDER BY HGL_LAYER_ID";  // SOURCE  FROM GS_NEW ";
                      break;
              case 4: endQuery = " AND ROWNUM <= 2000 ORDER BY DESCRIPTION"; // HGLDATE  FROM GS_NEW ";
                      break;
              case 5: endQuery = " AND ROWNUM <= 2000 ORDER BY DESCRIPTION";   // SCALE  FROM GS_NEW ";
                      break;
              default: ;
                       break;
          }
        
        
        int counter = 0; // Counter to determine AND, WHERE, or ORs

        /*
           Start building the query.
           The ? operator is a fuzzy search
           $ performs stemming and
           % is a wildcard character
        */
        
        theQuery = baseQuery + " WHERE ( ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/idinfo/citation/citeinfo/title)') > 1 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/idinfo/descript/abstract)') > 3 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/idinfo/citation/citeinfo/origin)') > 3 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/idinfo/citation/citeinfo/pubinfo/publish)') > 3 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/idinfo/keywords/theme/themekey)') > 1 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/idinfo/keywords/place/placekey)') > 1 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/idinfo/keywords/temporal/tempkey)') > 1 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/idinfo/keywords/stratum/stratkey)') > 1 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/eainfo/detailed/enttyp/enttypl)') > 1 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/eainfo/detailed/enttyp/enttypd)') > 1 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/eainfo/detailed/attr/attrlabl)') > 1 OR ";
        theQuery = theQuery + "contains(met_xml, '$"+myEntries[0]+" INPATH (/metadata/eainfo/detailed/attr/attrdef)') > 1 OR ";
        theQuery = theQuery + "contains(description, '$"+myEntries[0]+"') > 1 ";
   
        theQuery = theQuery + ")";
        
        counter = 0;

        for (int c = 1;c < myEntries.length;c++) {
            if (myEntries[c] != null && !myEntries[c].equals("")) {

                theQuery = theQuery + " AND ( ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/idinfo/citation/citeinfo/title)') > 1 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/idinfo/descript/abstract)') > 3 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/idinfo/citation/citeinfo/origin)') > 3 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/idinfo/citation/citeinfo/pubinfo/publish)') > 3 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/idinfo/keywords/theme/themekey)') > 1 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/idinfo/keywords/place/placekey)') > 1 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/idinfo/keywords/temporal/tempkey)') > 1 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/idinfo/keywords/stratum/stratkey)') > 1 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/eainfo/detailed/enttyp/enttypl)') > 1 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/eainfo/detailed/enttyp/enttypd)') > 1 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/eainfo/detailed/attr/attrlabl)') > 1 OR ";
                theQuery = theQuery + "contains(met_xml, '$"+myEntries[c]+" INPATH (/metadata/eainfo/detailed/attr/attrdef)') > 1 OR ";
                theQuery = theQuery + "contains(description, '$"+myEntries[c]+"') > 1 ";
                theQuery = theQuery + ")";        
            }
            
        }
                
        if (onlyCoords) {
          theQuery =  baseQuery + " WHERE ( "+ txtMapextWithin+ " ) " + endQuery;
        } else if (useCoords) {
            theQuery = theQuery + " AND ( "+ txtMapextWithin+ " ) " + endQuery;
        } else {
            theQuery = theQuery + endQuery;
        }
        
        return theQuery;
    }
    
    /**
     * Just removes bad characters like &, %, $ etc. from a query string. The
     * Jscript probably took care of it already so this is just a second check.
     */
    public static String stringScrubber(String tempString) {

        while (tempString.indexOf(" and ") > 0 )
            tempString = tempString.replaceAll(" and ", " ");
        while (tempString.indexOf(" AND ") > 0 )
            tempString = tempString.replaceAll(" AND ", "" );
        while (tempString.indexOf(" or ") > 0 )
            tempString = tempString.replaceAll(" or ", " ");
        while (tempString.indexOf(" OR ") > 0 )
            tempString = tempString.replaceAll(" OR ", " ");
        while (tempString.indexOf(" not ") > 0 )
            tempString = tempString.replaceAll(" not ", " ");
        while (tempString.indexOf(" NOT ") > 0 )
            tempString = tempString.replaceAll(" NOT ", " ");
        while (tempString.indexOf(" + ") > 0 )
            tempString = tempString.replaceAll("+", " ");
        while (tempString.indexOf("&") > 0 )
            tempString = tempString.replaceAll("&", " ");
        while (tempString.indexOf("(") > 0 )
            tempString = tempString.replaceAll("(", " ");
        while (tempString.indexOf(")") > 0 )
            tempString = tempString.replaceAll(")", " ");
        while (tempString.indexOf("'") > 1 )
            tempString = tempString.replaceAll("'", " ");
        while (tempString.indexOf(",") > 1 )
            tempString = tempString.replaceAll(",", " ");
        while (tempString.indexOf("\"") > 1 )
            tempString = tempString.replaceAll("\"", " ");
        while (tempString.indexOf("  ") > 1 )
            tempString = tempString.replaceAll("  ", " ");

        return tempString;
    }

}